using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Yoozoo.Modules.InnerCity.TouchCamera;

namespace BitBenderGames
{
    [Serializable]
    public class CameraDragParam
    {
        [Serializable]
        public class LodDragParam
        {
            [Range(0,5)]
            public int lodLevel;

            [Range(0,100)]
            public float lodPercent;
            
            public float dampFactorTimeMultiplier;

            public float autoScrollVelocityMax;
            
            public float autoScrollDamp;

        }
        
        public struct Damp
        {
            public float dampFactorTimeMultiplier;

            public float autoScrollVelocityMax;
            
            public float autoScrollDamp;
        }
        

        public LodDragParam[] LodDragParams;
        

        public void GetDamp(int lodLevel, float lodPercent,ref Damp damp)
        {

            bool isFind = false;
            for (int i = 0; i < LodDragParams.Length - 1; i++)
            {
                LodDragParam dragParam = LodDragParams[i];
                LodDragParam nextDragParam = LodDragParams[i+1];

                if (dragParam.lodLevel == nextDragParam.lodLevel )
                {
                    if (dragParam.lodLevel == lodLevel && dragParam.lodPercent <= lodPercent && nextDragParam.lodPercent>= lodPercent)
                    {
                        isFind = true;

                        float p = (lodPercent - dragParam.lodPercent) / (nextDragParam.lodPercent - dragParam.lodPercent);

                        damp.dampFactorTimeMultiplier =  (nextDragParam.dampFactorTimeMultiplier - dragParam.dampFactorTimeMultiplier) * p +
                            dragParam.dampFactorTimeMultiplier;
                        
                        damp.autoScrollVelocityMax =  (nextDragParam.autoScrollVelocityMax - dragParam.autoScrollVelocityMax) * p +
                                                          dragParam.autoScrollVelocityMax;
                        damp.autoScrollDamp =  (nextDragParam.autoScrollDamp - dragParam.autoScrollDamp) * p +
                                                          dragParam.autoScrollDamp;

                        break;
                    }
                    
                }
                else
                {
                    if (dragParam.lodLevel<=lodLevel && nextDragParam.lodLevel >= lodLevel)
                    {
                        isFind = true;

                       float totalPercent = (nextDragParam.lodLevel - dragParam.lodLevel) * 100 - dragParam.lodPercent +
                            nextDragParam.lodPercent;

                       float p = ((lodLevel - dragParam.lodLevel) * 100 - dragParam.lodPercent + lodPercent) /
                                 totalPercent;
                       
                       
                       damp.dampFactorTimeMultiplier =  (nextDragParam.dampFactorTimeMultiplier - dragParam.dampFactorTimeMultiplier) * p +
                                                        dragParam.dampFactorTimeMultiplier;
                        
                       damp.autoScrollVelocityMax =  (nextDragParam.autoScrollVelocityMax - dragParam.autoScrollVelocityMax) * p +
                                                     dragParam.autoScrollVelocityMax;
                       damp.autoScrollDamp =  (nextDragParam.autoScrollDamp - dragParam.autoScrollDamp) * p +
                                              dragParam.autoScrollDamp;
                       
                       break;
                    }
                    
                    
                }

                // 最后一个还没有找到信息，则使用最后一个的数据
                if (i == LodDragParams.Length - 2 && !isFind)
                {
                    float totalPercent = (nextDragParam.lodLevel - dragParam.lodLevel) * 100 - dragParam.lodPercent +
                                         nextDragParam.lodPercent;

                    float p = ((lodLevel - dragParam.lodLevel) * 100 - dragParam.lodPercent + lodPercent) /
                              totalPercent;
                       
                       
                    damp.dampFactorTimeMultiplier =  (nextDragParam.dampFactorTimeMultiplier - dragParam.dampFactorTimeMultiplier) * p +
                                                     dragParam.dampFactorTimeMultiplier;
                        
                    damp.autoScrollVelocityMax =  (nextDragParam.autoScrollVelocityMax - dragParam.autoScrollVelocityMax) * p +
                                                  dragParam.autoScrollVelocityMax;
                    damp.autoScrollDamp =  (nextDragParam.autoScrollDamp - dragParam.autoScrollDamp) * p +
                                           dragParam.autoScrollDamp;
                }
            }
        }
        
    }

    public class TouchCameraController : MonoBehaviour
    {
#if UNITY_EDITOR
        [XLua.BlackList]
        public Action onValidate;
#endif
        
        [DisplayOnly]
        public Camera Camera;
        [DisplayOnly]
        public Transform CameraTransform;
        [DisplayOnly]
        public MobileTouchCamera MobileTouchCamera;

        [SerializeField][DisplayOnly]
        private Vector2 BoundaryMin;
        [SerializeField][DisplayOnly]
        private Vector2 BoundaryMax;

        public float MAX_FOV = 30f;
        public float MIN_FOV = 5f;
        
        [DisplayOnly]
        public float ZoomDistanceMin = 7f;
        
        public float LOD1;
        public float LOD2;
        public float LOD3;
        public float LOD4;
        public float LOD5;
        public float ZoomDistanceMax = 7071f;

        [Header("是否使用自身的lod参数（目前用于内城）")]
        public bool isUseSelfLodParam;
        
        [Header("相机拖拽阻力参数")]
        public CameraDragParam CameraDragParam;


        [Space(10)]
        [Header("开启调试模式")]
        public bool DEBUG_MODE = false;
        
        [Header("阻力时间因子，和时间呈正线性比 Mathf.Clamp01(dampFactor = DampFactorTimeMultiplier * sinceTime)")]
        public float DebugDampFactorTimeMultiplier = 2f;
        [Header("最大起始速度的平方值,用于限制最大速度")]
        public float DebugAutoScrollVelocityMax = 400f;
        [Header("阻力基础系数")]
        public float DebugAutoScrollDamp = 3000f;

        [DisplayOnly]
        public float CurrentDampFactorTimeMultiplier;
        [DisplayOnly]
        public float CurrentAutoScrollVelocityMax;
        [DisplayOnly]
        public float CurrentAutoScrollDamp;
        
        [Space(10)]

        private float lastCameraHeight = -1f;

        private float CameraZoomInit = 0;
        
        private bool isInit = false;

        [SerializeField] 
        public Rect BoundRect = new Rect(0,0,1200,1200);
        public Rect GetBoundRect() { return BoundRect; }
        // 可拖拽范围，不受到相机的视野影响
        [SerializeField] 
        public bool DontChangeBoundWithVision = false;
    
        [SerializeField][DisplayOnly]
        private bool isLock;
        public bool IsLock => isLock;

        public Rect BoundEdgeRect = new Rect(0, 0, 0, 0);
        public PerspectiveZoomMode ZoomMode
        {
            get; 
            set;
        }

        public float TransEditorZoomFactor = 300;
        public float FovEditorZoomFactor = 100;
        
        [DisplayOnly]
        public bool BanModeUpdate = false;
        public bool CameraScaling = false;

        private List<CameraComponent> components = new List<CameraComponent>();

        public CameraGlobalValue CameraGlobalValue = new CameraGlobalValue();

        private void Start()
        {
            Camera = GetComponent<Camera>();
            CameraTransform = Camera.transform;
            MobileTouchCamera = GetComponent<MobileTouchCamera>();

            components = GetComponentsInChildren<CameraComponent>().ToList();
            foreach (var component in components)
            {
                component.cameraController = this;
            }
            
            MobileTouchCamera.OnCameraBound += OnCameraBound;
            MobileTouchCamera.OnSwicthMode += SwitchMode;
            
            Init();
        }

        public void Init(float[] lodArray = null)
        {
            if (CameraGlobalValue==null)
            {
                CameraGlobalValue = new CameraGlobalValue();
            }
            
            if (lodArray != null && lodArray.Length >= 5)
            {
                LOD1 = lodArray[0];
                LOD2 = lodArray[1];
                LOD3 = lodArray[2];
                LOD4 = lodArray[3];
                LOD5 = lodArray[5];
            }

            ZoomDistanceMin = LOD1;
            
            MobileTouchCamera.CamZoomMin = ZoomDistanceMin * 1.414f;
            MobileTouchCamera.CamZoomMax = ZoomDistanceMax * 1.414f;
            // 快速修复 bug https://jira.uuzu.com/browse/WARH-3734
            // CityCameraHelper.lua里设置了相机位置到ZoomMin的位置上
            // 但是此时的CamZoom值不在min值上，是一个超过max的值
            // 在下一个zoom更新中zoom值会被lerp到max值上。
            MobileTouchCamera.CamZoom = transform.position.y * 1.414f;
            MobileTouchCamera.ComputeCamBoundaries();
            MobileTouchCamera.PerspectiveZoomMode = PerspectiveZoomMode.TRANSLATION;
            ZoomMode = PerspectiveZoomMode.TRANSLATION;
            
            
            CameraGlobalValue.LODHeights = new float[7];
            
            CameraGlobalValue.MAX_FOV = MAX_FOV;
            CameraGlobalValue.MIN_FOV = MIN_FOV;

            CameraGlobalValue.ZoomDistanceMin = ZoomDistanceMin;
            CameraGlobalValue.LOD1Height = LOD1;
            CameraGlobalValue.LOD2Height = LOD2;
            CameraGlobalValue.LOD3Height = LOD3;
            CameraGlobalValue.LOD4Height = LOD4;
            CameraGlobalValue.LOD5Height = LOD5;
            CameraGlobalValue.ZoomDistanceMax = ZoomDistanceMax;

            CameraGlobalValue.LODHeights[0] = ZoomDistanceMin;
            CameraGlobalValue.LODHeights[1] = LOD1;
            CameraGlobalValue.LODHeights[2] = LOD2;
            CameraGlobalValue.LODHeights[3] = LOD3;
            CameraGlobalValue.LODHeights[4] = LOD4;
            CameraGlobalValue.LODHeights[5] = LOD5;
            CameraGlobalValue.LODHeights[6] = ZoomDistanceMax;

            isInit = true;
            CameraZoomInit = MobileTouchCamera.CamZoom;
            if (Yoozoo.Gameplay.GTAGameStart.eventManager != null)
            {
                Yoozoo.Gameplay.GTAGameStart.eventManager.TriggerEvent(Yoozoo.Mars.Got.ClientEvent.OnInitCityCameraEnd);
            }

#if UNITY_EDITOR || UNITY_STANDALONE_WIN
            MobileTouchCamera.TransEditorZoomFactor = TransEditorZoomFactor;
            MobileTouchCamera.FovEditorZoomFactor = FovEditorZoomFactor;
#endif
            
#if UNITY_EDITOR
            DebugComponent.GetInstance("Debugger");
#endif
        }

        public void UpdateZoomDistance(float zoomMin, float zoomMax, bool notChange = false)
        {
            ZoomDistanceMin = zoomMin;
            ZoomDistanceMax = zoomMax;

            MobileTouchCamera.CamZoomMin = ZoomDistanceMin * 1.414f;
            MobileTouchCamera.CamZoomMax = ZoomDistanceMax * 1.414f;
            // 快速修复 bug https://jira.uuzu.com/browse/WARH-3734
            // CityCameraHelper.lua里设置了相机位置到ZoomMin的位置上
            // 但是此时的CamZoom值不在min值上，是一个超过max的值
            // 在下一个zoom更新中zoom值会被lerp到max值上。
            MobileTouchCamera.CamZoom = transform.position.y * 1.414f;
            MobileTouchCamera.ComputeCamBoundaries(notChange);
            MobileTouchCamera.CamZoomDefault = transform.position.y * 1.414f;
        }

        public void UpdateCurrentLodParam(QualityLod qualityLod)
        {
            LOD1 = qualityLod.Lod1;
            LOD2 = qualityLod.Lod2;
            LOD3 = qualityLod.Lod3;
            LOD4 = qualityLod.Lod4;
            LOD5 = qualityLod.Lod5;
            MobileTouchCamera.SetLodHeight(
                LOD1,
                LOD2,
                LOD3,
                LOD4,
                LOD5);
            
        }

        private CameraDragParam.Damp _damp = new CameraDragParam.Damp();
#if UNITY_EDITOR

        private void Update()
        {
            

            CurrentDampFactorTimeMultiplier = MobileTouchCamera.DampFactorTimeMultiplier;
            CurrentAutoScrollVelocityMax = MobileTouchCamera.AutoScrollVelocityMax;
            CurrentAutoScrollDamp = MobileTouchCamera.AutoScrollDamp ;
            
            if (!BanModeUpdate)
            {
                if (_nextZoomMode != ZoomMode)
                {
                    if (ZoomMode == PerspectiveZoomMode.TRANSLATION)
                    {
                        // 切换为FOV模式
                        MobileTouchCamera.PerspectiveZoomMode = PerspectiveZoomMode.FIELD_OF_VIEW;
                        MobileTouchCamera.CamZoomMin = MIN_FOV;
                        MobileTouchCamera.CamZoomMax = MAX_FOV;
                        ZoomMode = PerspectiveZoomMode.FIELD_OF_VIEW;
                    }
                    else if (ZoomMode == PerspectiveZoomMode.FIELD_OF_VIEW)
                    {
                        // 切换为高度模式
                        MobileTouchCamera.PerspectiveZoomMode = PerspectiveZoomMode.TRANSLATION;
                        MobileTouchCamera.CamZoomMin = ZoomDistanceMin * 1.414f;
                        MobileTouchCamera.CamZoomMax = ZoomDistanceMax * 1.4145f;
                        ZoomMode = PerspectiveZoomMode.TRANSLATION;
                    }
                }

            }

            //
            // if (Input.GetKeyDown((KeyCode) ((int) KeyCode.Alpha1)))
            // {
            //     WorldMapUtility.ZoomLOD(0,0f,0.3f);
            //     //StartCoroutine(MobileTouchCamera.ZoomToTargetValueCoroutine(ZoomDistanceMin * 1.415f));
            // }
            // if (Input.GetKeyDown((KeyCode) ((int) KeyCode.Alpha2)))
            // {
            //     WorldMapUtility.ZoomLOD(1,1f,0.3f);
            //     //StartCoroutine(MobileTouchCamera.ZoomToTargetValueCoroutine(WorldEntry.DISTANCE_LOD0* 1.415f));
            // }
            // if (Input.GetKeyDown((KeyCode) ((int) KeyCode.Alpha3)))
            // {
            //     WorldMapUtility.ZoomLOD(2,0.1f,0.3f);
            //     //StartCoroutine(MobileTouchCamera.ZoomToTargetValueCoroutine(WorldEntry.DISTANCE_LOD1* 1.415f));
            // }
            // if (Input.GetKeyDown((KeyCode) ((int) KeyCode.Alpha4)))
            // {
            //     WorldMapUtility.ZoomLOD(3,0.1f,0.3f);
            //     //StartCoroutine(MobileTouchCamera.ZoomToTargetValueCoroutine(WorldEntry.DISTANCE_LOD2* 1.415f));
            // }
            // if (Input.GetKeyDown((KeyCode) ((int) KeyCode.Alpha5)))
            // {
            //     WorldMapUtility.ZoomLOD(4,0.1f,0.3f);
            //     //StartCoroutine(MobileTouchCamera.ZoomToTargetValueCoroutine(WorldEntry.DISTANCE_LOD3* 1.415f));
            // }
            // if (Input.GetKeyDown((KeyCode) ((int) KeyCode.Alpha6)))
            // {
            //     WorldMapUtility.ZoomLOD(5,0.1f,0.3f);
            //     //StartCoroutine(MobileTouchCamera.ZoomToTargetValueCoroutine(WorldEntry.DISTANCE_LOD4* 1.415f));
            // }
            // if (Input.GetKeyDown((KeyCode) ((int) KeyCode.Alpha7)))
            // {
            //     WorldMapUtility.ZoomLOD(5,100,0.3f);
            //     //StartCoroutine(MobileTouchCamera.ZoomToTargetValueCoroutine(ZoomDistanceMax* 1.415f));
            // }
        }
        
#endif

        public K GetCameraComponet<K>() where K : CameraComponent
        {
            for (int i = 0; i < components.Count; i++)
            {
                if (components[i] is K)
                {
                    return components[i] as K;
                }
            }
            return null;
        }
        

        private void OnCameraBound(float width, float height)
        {
            if (!DontChangeBoundWithVision)
            {
                BoundaryMin.x = BoundRect.x - width / 2 + BoundEdgeRect.x;
                BoundaryMax.x = BoundRect.size.x + width / 2 + BoundEdgeRect.width;
                BoundaryMin.y = BoundRect.y - height / 2 + BoundEdgeRect.y;
                BoundaryMax.y = BoundRect.size.y + height / 2 + BoundEdgeRect.height;
                
                MobileTouchCamera.BoundaryMin = BoundaryMin;
                MobileTouchCamera.BoundaryMax = BoundaryMax;
            }
        }


        public void SetCameraLockStatus(bool lockStatus)
        {
            isLock = lockStatus;
            MobileTouchCamera.Locked = isLock;
        }

        public void SetCameraDoubleDragStatus(bool canDrag)
        {
            MobileTouchCamera.CanDoubleDrag = canDrag;
        }

        public void SetCameraZoomByScale(float scale)
        {
            MobileTouchCamera.SetCameraZoomByScale(scale);
        }


        public void SetCameraBoundary(Rect bound)
        {
            BoundRect = bound;
            MobileTouchCamera.ComputeCamBoundaries();
        }

        public void SetLOD0MinPercent(float minPercent)
        {
            if (MobileTouchCamera.PerspectiveZoomMode == PerspectiveZoomMode.FIELD_OF_VIEW)
            {
                float minFov = (CameraGlobalValue.MAX_FOV - CameraGlobalValue.MIN_FOV) * minPercent * 0.01f + CameraGlobalValue.MIN_FOV;
                MobileTouchCamera.CamZoomMin = minFov;
            }
        }

        public void SetLOD0MaxPercent(float manPercent)
        {
            float manFov = (CameraGlobalValue.MAX_FOV - CameraGlobalValue.MIN_FOV) * manPercent * 0.01f + CameraGlobalValue.MIN_FOV;
            MobileTouchCamera.CamZoomMax = manFov;
        }

        private int lastLodLevel = -1;
        private float lastLodPercent = -1;
        
        
        private void LateUpdate()
        {
            int lodLevel;
            float lodPercent;
            if (isUseSelfLodParam)
            {
                SetDampParam(MobileTouchCamera.LastLODLevel, MobileTouchCamera.LastLODPercent);
            }
            else
            {
                if (DynamicLayerMgr.worldEntry!=null)
                {
                    lodLevel = DynamicLayerMgr.worldEntry.GetLODLevel();
                    lodPercent = DynamicLayerMgr.worldEntry.GetLODPercent();
                    SetDampParam(lodLevel, lodPercent);
                }
            }
            
            
//                float lodHeight = CameraTransform.position.y;
//                //float lodPercent = (lodHeight - ZoomDistanceMin) / (ZoomDistanceMax - ZoomDistanceMin);
//                float lodPercent = lodHeight / ZoomDistanceMax;
//                //float lodPercentSqr = lodPercent * lodPercent;
//
//                MobileTouchCamera.AutoScrollDamp = lodPercent * AutoScrollDamp + MinDampVelocity * (AutoScrollDamp/MaxAutoScrollVelFactor);
//                MobileTouchCamera.AutoScrollVelocityMax = lodPercent * MaxAutoScrollVelFactor + MinDampVelocity;

#if UNITY_EDITOR

            if (DEBUG_MODE)
            {
                MobileTouchCamera.DampFactorTimeMultiplier = DebugDampFactorTimeMultiplier;
                MobileTouchCamera.AutoScrollVelocityMax = DebugAutoScrollVelocityMax;
                MobileTouchCamera.AutoScrollDamp = DebugAutoScrollDamp;
            }
#endif



            foreach (var component in components)
            {
                component.OnLateUpdate();
            }
            
        }
        

        public PerspectiveZoomMode _nextZoomMode = PerspectiveZoomMode.TRANSLATION;
        
        private void SwitchMode(PerspectiveZoomMode zoomMode)
        {
            _nextZoomMode = zoomMode;
        }

        private void SetDampParam(int lodLevel, float lodPercent)
        {
            if (lodLevel!=lastLodLevel || Math.Abs(lastLodPercent - lodPercent) > 0.01  )
            {
                CameraDragParam.GetDamp(lodLevel,lodPercent,ref _damp);

                MobileTouchCamera.DampFactorTimeMultiplier = _damp.dampFactorTimeMultiplier;
                MobileTouchCamera.AutoScrollVelocityMax = _damp.autoScrollVelocityMax;
                MobileTouchCamera.AutoScrollDamp = _damp.autoScrollDamp;

                lastLodLevel = lodLevel;
                lastLodPercent = lodPercent;
            }
        }

        public float GetCameraZoomInit()
        {
            return CameraZoomInit;
        }
        
        
#if UNITY_EDITOR
        [XLua.BlackList]
        public void OnValidate()
        {
            if (!isInit)
            {
                return;
            }
            
            onValidate?.Invoke();
            
            MobileTouchCamera.TransEditorZoomFactor = TransEditorZoomFactor;
            MobileTouchCamera.FovEditorZoomFactor = FovEditorZoomFactor;
            
            CameraGlobalValue.MAX_FOV = MAX_FOV;
            CameraGlobalValue.MIN_FOV = MIN_FOV;
            
            ZoomDistanceMin = LOD1;
            
            if (MobileTouchCamera.PerspectiveZoomMode == PerspectiveZoomMode.TRANSLATION)
            {
                MobileTouchCamera.CamZoomMin = ZoomDistanceMin * 1.414f;
                MobileTouchCamera.CamZoomMax = ZoomDistanceMax * 1.4145f;
            }
            else
            {
                MobileTouchCamera.CamZoomMin = MIN_FOV;
                MobileTouchCamera.CamZoomMax = MAX_FOV;
            }


            CameraGlobalValue.ZoomDistanceMin = ZoomDistanceMin;
            CameraGlobalValue.LOD1Height = LOD1;
            CameraGlobalValue.LOD2Height = LOD2;
            CameraGlobalValue.LOD3Height = LOD3;
            CameraGlobalValue.LOD4Height = LOD4;
            CameraGlobalValue.LOD5Height = LOD5;
            CameraGlobalValue.ZoomDistanceMax = ZoomDistanceMax;
            
            CameraGlobalValue.LODHeights[0] = ZoomDistanceMin;
            CameraGlobalValue.LODHeights[1] = LOD1;
            CameraGlobalValue.LODHeights[2] = LOD2;
            CameraGlobalValue.LODHeights[3] = LOD3;
            CameraGlobalValue.LODHeights[4] = LOD4;
            CameraGlobalValue.LODHeights[5] = LOD5;
            CameraGlobalValue.LODHeights[6] = ZoomDistanceMax;
            
        }
#endif
    }
}
